using System;
using System.Collections;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

using Server.Manager;

using Domain;

namespace Server
{
    struct cCon
    {
        public Player p;
        public Socket conn;
    }
    class Server
    {
        private static Server instance;

        // Socket
        private Socket host;
        private ArrayList clients; 

        // Constructor
        private Server()
        {
            clients = new ArrayList();
        }

        // Server functions
        public bool Listen(int port)
        {
            try
            {
                // Create socket
                host = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                // Bind socket to port
                host.Bind(new IPEndPoint(IPAddress.Any, port));

                // Start listening
                host.Listen(32);

                // Create thread
                Thread thread = new Thread(new ParameterizedThreadStart(ConnectionProc));
                thread.IsBackground = true;

                // Start thread
                thread.Start(host);

                return true;
            }

            catch (SocketException e)
            {
                Console.WriteLine(e);

                return false;
            }
        }

        public bool Send(String message)
        {
            return false;
        }

        public bool Close()
        {
            try
            {
                host.Close();

                return true;
            }

            catch (SocketException e)
            {
                Console.WriteLine(e);

                return false;
            }
        }

        // Callbacks
        private void WaitForData(Socket socket)
        {

        }

        private void OnClientConnect(IAsyncResult asyn)
        {

        }

        private void OnClientDisconnect(IAsyncResult asyn)
        {

        }

        private void OnDataReceived(IAsyncResult asyn)
        {

        }

        // Replace this
        private void ConnectionProc(object obj)
        {
            Socket host = (Socket)obj;
            Socket client = null;

            string message;
            byte[] data;
            int length;

            try
            {
                client = host.Accept();
                Console.WriteLine("incoming connection...");
                while (true)
                {
                    String name = "";
                    // Retrieve data
                    data = new byte[256];
                    length = client.Receive(data);
                    message = Encoding.ASCII.GetString(data, 0, length);

                    if (message.StartsWith("/name"))
                    {
                        name = message.Split(' ')[1];
                        cCon c = new cCon();
                        c.p = new Player(name);
                        c.conn = client;
                        clients.Add(c);
                        foreach (cCon pla in clients)
                        {
                            byte[] dat = Encoding.ASCII.GetBytes("/from " + name + " /joined");
                            if (pla.p.Name != name) pla.conn.Send(dat);
                        }
                        Console.WriteLine(name + " joined");
                    }
                    else
                    {
                        Console.WriteLine(name + " has send:" + message);
                        foreach (cCon pla in clients)
                        {
                            byte[] dat = Encoding.ASCII.GetBytes("/from " + name + " " + message);
                            if (pla.p.Name != name) pla.conn.Send(dat);
                            if( message.StartsWith("/exit") )
                            {
                                pla.conn.Shutdown(SocketShutdown.);
                                pla.conn.Close();
                                clients.Remove(pla);
                            }
                        }
                    }
                }
            }

            catch (SocketException e)
            {
                if (client != null)
                {
                    // Close client
                    client.Shutdown(SocketShutdown.Both);
                    client.Close();
                }

                Console.WriteLine(e);
            }
        }

        // Accessors
        public static Server Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Server();
                }

                return instance;
            }
        }

        public ArrayList Clients
        {
            get
            {
                return clients;
            }
        }
    }
}
